package me.yricky.mayu.ui.tasks.taskui.seqali

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transform
import kotlinx.coroutines.withContext
import me.yricky.mayu.ui.tasks.taskui.Task
import me.yricky.mayu.ui.tasks.taskui.TaskStatus
import me.yricky.mayu.ui.fasta.FastaSeqModel
import me.yricky.mayu.utils.misc.reduceNullable
import me.yricky.mayu.utils.sequence.SequenceAlignmentSession
import java.text.SimpleDateFormat
import java.util.*

/**
 * @author Yricky
 * @date 2022/4/20
 */
class SeqAlignmentTask(
    val seq1: FastaSeqModel,
    val seq2: FastaSeqModel,
    pairScore:(Char,Char)->Int = SequenceAlignmentSession.simpleMatchPairScore(),
    vacancyScore:Int = -2,
): Task {
    val session = SequenceAlignmentSession(seq1, seq2, pairScore, vacancyScore){
        status = Finished
    }
    val memConsumeMB:Int = (seq1.seq.size.toDouble() * seq2.seq.size * 4 / 1024 / 1024).toInt().coerceAtLeast(1)
    val scope = CoroutineScope(Dispatchers.Default)
    override val name: String = "序列比对任务(${SimpleDateFormat("H:mm:ss").format(Date())})"
    override var status: TaskStatus by mutableStateOf(Idle)

    val resultList = flow {
        emit(
            withContext(Dispatchers.Default) {
                session.traceIterator(session.result.second.last()).asSequence().toList().asReversed()
            }
        )
    }.stateIn(scope, SharingStarted.WhileSubscribed(), emptyList())

    val firstRange = resultList.transform { value: List<Pair<Int, Int>> ->
        emit(
            reduceNullable(value.firstOrNull { it.first >= 0 }?.first,value.lastOrNull{ it.first >= 0 }?.first){ i1,i2->
                IntRange(i1,i2)
            }?: IntRange.EMPTY
        )
    }.stateIn(scope, SharingStarted.WhileSubscribed(),IntRange.EMPTY)

    val secondRange = resultList.transform { value: List<Pair<Int, Int>> ->
        emit(
            reduceNullable(value.firstOrNull { it.second >= 0 }?.second,value.lastOrNull{ it.second >= 0 }?.second){ i1,i2->
                IntRange(i1,i2)
            }?: IntRange.EMPTY
        )
    }.stateIn(scope, SharingStarted.WhileSubscribed(),IntRange.EMPTY)
}



